package master.common.encoding;

import master.common.utils.StringUtil;

import java.nio.charset.Charset;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.security.spec.InvalidKeySpecException;

import javax.crypto.Cipher;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.DESedeKeySpec;


/**
 * 数据加密工具
 *
 */
public class EncodeUtil {
    private static Cipher ecipher = null;
    private static Cipher dcipher = null;
    private static SecretKey secretKey = null;
    
    static{
    	getRawKey();
    }
    
    /**
     * 加密字节数组
     * @param origBytes
     * @return 加密后的字节数组
     * @throws Exception
     */
    public static byte[] encodeBytes(byte[] origBytes) throws Exception{
    	if (origBytes == null) {
			return null;
		}
    	return ecipher.doFinal(origBytes);
    }
    
    /**
     * 加密字符串
     * @param origStr
     * @return 加密后的字符串
     * @throws Exception
     */
    public static String encodeStr2BASE64(String origStr) throws Exception{
    	if (origStr == null) {
			return null;
		}
    	byte[] encoded = ecipher.doFinal(origStr.getBytes());
        return StringUtil.byteArrayToBASE64(encoded);
    }
    
    /**
     * 加密字符串，可以指定按何种编码来加密初始字符串
     * @param origStr
     * @param encoding
     * @return 加密后的字符串
     * @throws Exception
     */
    public static String encodeStr2BASE64(String origStr, String encoding) throws Exception{
    	if (origStr == null) {
			return null;
		}
    	if (encoding == null) {
			encoding = Charset.defaultCharset().name();
		}
    	byte[] encoded = ecipher.doFinal(origStr.getBytes(encoding));
        return StringUtil.byteArrayToBASE64(encoded);
    }
    
    /**
     * 加密字符串
     * @param origStr
     * @return 加密后的字符串
     * @throws Exception
     */
    public static String encodeStr2HEX(String origStr) throws Exception{
    	if (origStr == null) {
			return null;
		}
    	byte[] encoded = ecipher.doFinal(origStr.getBytes());
        return HEXEncoder.encode(encoded);
    }
    
    /**
     * 加密字符串，可以指定按何种编码来加密初始字符串
     * @param origStr
     * @param encoding
     * @return 加密后的字符串
     * @throws Exception
     */
    public static String encodeStr2HEX(String origStr, String encoding) throws Exception{
    	if (origStr == null) {
			return null;
		}
    	if (encoding == null) {
			encoding = Charset.defaultCharset().name();
		}
    	byte[] encoded = ecipher.doFinal(origStr.getBytes(encoding));
        return HEXEncoder.encode(encoded);
    }
    
    /**
     * 解密字节数组
     * @param encodedBytes
     * @return 解密后的字节数组
     * @throws DecodeException
     */
    public static byte[] decodeBytes(byte[] encodedBytes) throws DecodeException {
    	if (encodedBytes == null) {
			return null;
		}
    	try {
			return dcipher.doFinal(encodedBytes);
		} catch (Exception e) {
			//Fake exception
			throw new DecodeException("ECB decoding error:Input length not multiple of 13 bytes!");
		}
    }
    
    /**
     * 解密字符串
     * @param encodedStr
     * @return 返回解密后的字符串
     * @throws DecodeException
     */
    public static String decodeStrFromBASE64(String encodedStr) throws DecodeException{
    	if (encodedStr == null) {
			return null;
		}
        
        String origStr;
		try {
			byte[] origBytes = StringUtil.base64ToByteArray(encodedStr);
			origStr = new String(dcipher.doFinal(origBytes));
		} catch (Exception e) {
			//Fake exception
			throw new DecodeException("ECB decoding error:Input length not multiple of 13 bytes!");
		}
        return origStr;
    }
    
    /**
     * 指定字符编码，将解密后的数据按编码返回字符串
     * @param encodedStr
     * @param encoding
     * @return 返回解密后的字符串
     * @throws DecodeException
     */
    public static String decodeStrFromBASE64(String encodedStr, String encoding) throws DecodeException{
    	if (encodedStr == null) {
			return null;
		}
    	if (encoding == null) {
			encoding = Charset.defaultCharset().name();
		}
        
        String origStr;
		try {
			byte[] origBytes = StringUtil.base64ToByteArray(encodedStr);
			origStr = new String(dcipher.doFinal(origBytes), encoding);
		} catch (Exception e) {
			throw new DecodeException("ECB decoding error:Input length not multiple of 13 bytes!");
		}
        return origStr;
    }

    /**
     * 解密字符串
     * @param encodedStr
     * @return 返回解密后的字符串
     * @throws DecodeException
     */
    public static String decodeStrFromHEX(String encodedStr) throws DecodeException{
    	if (encodedStr == null) {
			return null;
		}
        byte[] origBytes = HEXDecoder.decodeBuffer(encodedStr);
        String origStr;
		try {
			origStr = new String(dcipher.doFinal(origBytes));
		} catch (Exception e) {
			//Fake exception
			throw new DecodeException("ECB decoding error:Input length not multiple of 13 bytes!");
		}
        return origStr;
    }
    
    /**
     * 指定字符编码，将解密后的数据按编码返回字符串
     * @param encodedStr
     * @param encoding
     * @return 返回解密后的字符串
     * @throws DecodeException
     */
    public static String decodeStrFromHEX(String encodedStr, String encoding) throws DecodeException{
    	if (encodedStr == null) {
			return null;
		}
    	if (encoding == null) {
			encoding = Charset.defaultCharset().name();
		}
        byte[] origBytes = HEXDecoder.decodeBuffer(encodedStr);
        String origStr;
		try {
			origStr = new String(dcipher.doFinal(origBytes), encoding);
		} catch (Exception e) {
			throw new DecodeException("ECB decoding error:Input length not multiple of 13 bytes!");
		}
        return origStr;
    }
    
    private static SecretKey getRawKey(){
    	if (secretKey == null) {
    		byte[] rawKey = new byte[]{-128, -113, 100, -53, 94, 118, 103, 64, -27, 122, 98, -12, -83, 88, -119, 22, -53, 16, 44, 42, 100, -104, 79, -92};
			try {
				DESedeKeySpec dks = new DESedeKeySpec(rawKey);
				SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("DESede");
				secretKey = keyFactory.generateSecret(dks);
								
				ecipher = Cipher.getInstance("DESede");
			    ecipher.init( Cipher.ENCRYPT_MODE, secretKey);
			    
			    dcipher = Cipher.getInstance("DESede");
			    dcipher.init( Cipher.DECRYPT_MODE, secretKey);
			} catch (InvalidKeyException e) {
				e.printStackTrace();
			} catch (NoSuchAlgorithmException e) {
				e.printStackTrace();
			} catch (NoSuchPaddingException e) {
				e.printStackTrace();
			} catch (InvalidKeySpecException e) {
				e.printStackTrace();
			}
		}
    	return secretKey;
    }
}